package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.lkd.common.VMSystem;
import com.lkd.config.ConsulConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.contract.VendoutResultContract;
import com.lkd.dao.OrderDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.UserService;
import com.lkd.feign.VMService;
import com.lkd.service.OrderService;
import com.lkd.utils.DistributedLock;
import com.lkd.vo.PartnerVO;
import com.lkd.vo.PayVO;
import com.lkd.vo.SkuVO;
import com.lkd.vo.VmVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    private VMService vmService;

    @Autowired
    private UserService userService;

    @Autowired
    private MqttProducer mqttProducer;
    @Autowired
    private ConsulConfig consulConfig;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo, orderNo);
        return this.getOne(qw);
    }

    /**
     * 微信小程序支付创建订单
     *
     * @param payVO
     * @return
     */
    @Override
    public OrderEntity createOrder(PayVO payVO) {

        //当前商品是否售罄
        Boolean flag = vmService.hasCapacity(payVO.getInnerCode(), Long.parseLong(payVO.getSkuId()));
        if (!flag) {
            throw new LogicException("该商品已售空");
        }


        //分布式锁，机器同一时间只能处理一次出货
        //获取分布式锁
        DistributedLock distributedLock = new DistributedLock(
                consulConfig.getConsulRegisterHost(),
                consulConfig.getConsulRegisterPort()
        );
        //获取锁对象 参数,锁名,过期时间秒
        DistributedLock.LockContext lockContext = distributedLock.getLock("key", 60);
        if (!lockContext.isGetLock()) {
            //获取锁失败
            throw new LogicException("机器出货中请稍后再试");

        }
        //将锁存入redis //存入redis后是为了释放锁
        //绑定一个人key对象
        redisTemplate.boundValueOps(VMSystem.VM_LOCK_KEY_PREF + payVO.getInnerCode())
                //给绑定键重新设置值(如果没有值，则会添加这个值),设置过期时间60秒
                .set(lockContext.getSession(), Duration.ofSeconds(60));


        //创建订单实体
        OrderEntity orderEntity = new OrderEntity();

        BeanUtils.copyProperties(payVO, orderEntity);
        //订单编号:售货机编号+当前时间纳秒
        orderEntity.setOrderNo(payVO.getInnerCode() + System.nanoTime());

        //售货机属性
        VmVO vmInfo = vmService.getVMInfo(payVO.getInnerCode());
        BeanUtils.copyProperties(vmInfo, orderEntity);
        //地址
        orderEntity.setAddr(vmInfo.getNodeAddr());

        //商品属性
        SkuVO sku = vmService.getSku(payVO.getSkuId());
        BeanUtils.copyProperties(sku, orderEntity);
        //设置支付金额
        orderEntity.setAmount(sku.getRealPrice());
        //设置订单状态
        orderEntity.setStatus(VMSystem.ORDER_STATUS_CREATE);

        //合作人
        PartnerVO partner = userService.getPartner(vmInfo.getOwnerId());
        //分账金额
        int bill = new BigDecimal(sku.getRealPrice())
                .multiply(new BigDecimal(partner.getRatio()))
                .divide(new BigDecimal(100), 0, RoundingMode.HALF_UP)
                .intValue();
        orderEntity.setBill(bill);


        this.save(orderEntity);

        //创建协议对象
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setOrderNo(orderEntity.getOrderNo());
        orderCheck.setInnerCode(orderEntity.getInnerCode());
        //发送延迟消息
        try {
            //EMQ发送延迟消息,订单若微支付10min后过期
            mqttProducer.send("$delayed/600/" + TopicConfig.ORDER_CHECK_TOPIC, 2, orderCheck);
        } catch (JsonProcessingException e) {
            log.error("修改订单状态延时任务", e);
        }


        return orderEntity;
    }


    /**
     * 发送出货通知
     * 调用售货机微服务,修改订单状态,库存
     *
     * @param orderNo 微信支付后回调参数 解析的订单编号
     */
    @Override
    public boolean vendout(String orderNo) {
        //根据点单编号查询订单
        OrderEntity orderEntity = this.getByOrderNo(orderNo);
        //修改订单状态
        orderEntity.setStatus(VMSystem.ORDER_STATUS_PAYED);
        //修改支付状态
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_PAYED);
        this.updateById(orderEntity);
        //封装出货协议
        VendoutData vendoutData = new VendoutData();
        vendoutData.setOrderNo(orderNo);
        vendoutData.setSkuId(orderEntity.getSkuId());
        VendoutContract vendoutContract = new VendoutContract();
        vendoutContract.setVendoutData(vendoutData);
        vendoutContract.setInnerCode(orderEntity.getInnerCode());
        //向售货机微服务发送消息
        try {
            mqttProducer.send(TopicConfig.VMS_VENDOUT_TOPIC, 2, vendoutContract);
        } catch (JsonProcessingException e) {
            log.error("send vendout req error.", e);
            return false;
        }
        return true;

    }

    /**
     * 订单位服务根据终端响应信息修改订单状态
     *
     * @param vendoutResultContract
     * @return
     */
    @Override
    public boolean VendoutResult(VendoutResultContract vendoutResultContract) {

        //获取订单编号
        String orderNo = vendoutResultContract.getVendoutData().getOrderNo();

        if (vendoutResultContract.isSuccess()) {
            //出货成功
            this.update(
                    Wrappers.<OrderEntity>lambdaUpdate()
                            .eq(OrderEntity::getOrderNo, orderNo)
                            .set(OrderEntity::getStatus, VMSystem.ORDER_STATUS_VENDOUT_SUCCESS)
            );
            return true;
        } else {
            //出货失败
            this.update(
                    Wrappers.<OrderEntity>lambdaUpdate()
                            .eq(OrderEntity::getOrderNo, orderNo)
                            .set(OrderEntity::getStatus, VMSystem.ORDER_STATUS_VENDOUT_FAIL)
            );
            return false;
            //TODO: 出货失败退款
        }

    }

}
